package com.behelpful.demo.gateway.provider;

import com.behelpful.demo.gateway.config.FilterIgnoreProperties;
import com.behelpful.demo.gateway.locator.RouteDefinitionWriterAndReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Swagger 资源整合
 *
 * @author Alay
 * @date 2021-09-05 22:05
 * @since
 */
@Component
@Primary
public class ISwaggerResourcesProvider implements SwaggerResourcesProvider {

    public static final String API_URI_2 = "/v2/api-docs";
    public static final String API_URI_3 = "/v3/api-docs";

    @Autowired
    private RouteDefinitionWriterAndReader routeWriterAndReader;
    /**
     * Swagger 加载资源时忽略的模块
     */
    @Autowired
    private FilterIgnoreProperties ignoreServer;

    @Override
    public List<SwaggerResource> get() {
        // 路由数据集合
        List<RouteDefinition> routes = new ArrayList<>();

        Flux<RouteDefinition> routeDefinitions = routeWriterAndReader.getRouteDefinitions();
        // 将 网关中所有的路由信息集合在一起
        routeDefinitions.subscribe(routes::add);

        List<SwaggerResource> swaggerResources = routes.stream()
                .filter(route -> !ignoreServer.getSwaggerProviders().contains(route.getId()))
                .flatMap(route ->
                        route.getPredicates()
                                .stream()
                                // 路径与断言配置匹配(忽略大小写),必须匹配 /Path
                                .filter(predicate -> "Path".equalsIgnoreCase(predicate.getName()))
                                .filter(predicate -> !ignoreServer.getSwaggerProviders().contains(predicate.getName()))
                                .map(predicate -> {

                                    String routeId = route.getId();

                                    String location = predicate.getArgs()
                                            .get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                            .replace("/**", API_URI_2);

                                    SwaggerResource swaggerResource = this.builderResource(routeId, location);

                                    return swaggerResource;
                                })

                ).sorted(Comparator.comparing(SwaggerResource::getName))
                .collect(Collectors.toList());
        return swaggerResources;
    }

    /**
     * 构建Swagger数据源
     *
     * @param name
     * @param location
     * @return
     */
    private SwaggerResource builderResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setSwaggerVersion("3.0");
        swaggerResource.setLocation(location);
        return swaggerResource;
    }
}